package com.neardrug.system;

import cn.hutool.core.io.FileUtil;
import com.neardrug.common.Constants;
import com.neardrug.entity.*;
import com.neardrug.exception.ServiceException;
import com.neardrug.mapper.*;
import com.neardrug.services.ExamplesService;
import com.neardrug.utils.ApiUtil;
import com.neardrug.utils.SpringUtils;
import com.neardrug.vo.MarkdownVO;
import com.neardrug.vo.RecordVO;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.TrustAllStrategy;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import org.json.JSONArray;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.net.ssl.SSLContext;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.CompletableFuture;


/**
 * 管理所有多线程任务的线程工厂类
 */
public class AsyncTaskFactory {

    private static final ThreadPoolTaskExecutor EXECUTOR= SpringUtils.getBean("threadPoolTaskExecutor");
    //定义出文件的目录 其中前者为整个项目的根目录
    private static final String filePath=System.getProperty("user.dir")+"/files/";

    private static final String fileBaseUrl= StaticProvider.getFileBaseUrl();
    private static final AnalysisMapper analysisMapper=StaticProvider.getAnalysisMapper();
    private static final MarkdownMapper markdownMapper=StaticProvider.getMarkdownMapper();
    private static final RecordMapper recordMapper=StaticProvider.getRecordMaooer();
    private static final ExamplesMapper examplesMapper=StaticProvider.getExamplesMapper();
    private static final ExamplesService examplesService=StaticProvider.getExamplesService();
    private static final ImagesMapper imagesMapper=StaticProvider.getImagesMapper();
    private static final FormImgMapper formImgMapper=StaticProvider.getFormImgMapper();
    private static final FormTableMapper formTableMapper=StaticProvider.getFormTableMapper();
    private static final Logger log = LoggerFactory.getLogger(AsyncTaskFactory.class);

    /**
     * 调用markdown的API并返回markdown结果
     * @param file
     * @param userId
     * @return
     */
    public static CompletableFuture<MarkdownVO> api(MultipartFile file, Integer userId) {
        return CompletableFuture.supplyAsync(() -> {
            // 定义保存文件的路径
            String uploadDir = filePath;
            if (!FileUtil.isDirectory(filePath)){
                FileUtil.mkdir(filePath);
            }

            //获取文件名(不包含扩展名)
            String originalFileName=file.getOriginalFilename();
            String fileNameWithoutExtension=originalFileName.substring(0,originalFileName.indexOf("."));

            //定义本地系统中文件的唯一标识
            String fileName=System.currentTimeMillis()+"-"+ userId+"-"+file.getOriginalFilename();
            File dest = new File(uploadDir + fileName);

            //try(CloseableHttpClient client = HttpClients.createDefault()) {
            try (CloseableHttpClient client = createHttpClient()) {

                // 将上传的文件内容写入目标文件
                file.transferTo(dest);

                String markdownUrl = "https://lilab.ecust.edu.cn/nougat_predict"; // API URL


                //创建一个HTTP POST请求，指定请求的URL。
                HttpPost post = new HttpPost(markdownUrl);

                // 从files文件中获取文件
                String filePath = "files/"+fileName;
                File localFile = new File(filePath);

                MultipartEntityBuilder builder = MultipartEntityBuilder.create();
                builder.addBinaryBody("file", localFile); // 添加文件

                post.setEntity(builder.build());


                LocalDateTime createTime = LocalDateTime.now();//记录请求发起时间
                HttpResponse response = client.execute(post);
                LocalDateTime finishTime=LocalDateTime.now();//记录请求结束时间

                //获取请求响应状态码
                int statusCode = response.getStatusLine().getStatusCode();
                log.info("the api response status is:{}",statusCode);
                if (statusCode==200){//如果请求响应正确
                    // 读取响应体
                    BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
                    StringBuilder responseBody = new StringBuilder();
                    String line;
                    while ((line = reader.readLine()) != null) {
                        responseBody.append(line);
                    }

                    // 获取原始JSON字符串
                    String apiResult = responseBody.toString();
                    // 解析 JSON 响应体
                    JSONObject jsonResponse = new JSONObject(responseBody.toString());
                    String markdownResult = jsonResponse.optString("md_content","");
                    String recordResult= jsonResponse.optString("basic_data_json","");
                    JSONArray exampleResult = jsonResponse.optJSONArray("example_data");
                    JSONObject middleContent = jsonResponse.optJSONObject("middle_content");
                    JSONArray contentList=jsonResponse.optJSONArray("content_list");


                    //返回访问文件url
                    //String fileUrl=fileBaseUrl+"/files/"+fileName;//原来一长串的文件访问路径版本
                    String fileUrl=fileName;


                    //构建analysis对象
                    Analysis analysis=Analysis.builder()
                                    .userId(userId)
                                    .fileName(file.getOriginalFilename())
                                    .status("分析完成")
                                    .createTime(createTime)
                                    .finishTime(finishTime)
                                    .fileUrl(fileUrl)
                                    .build();
                    //对analysisMapper做插入操作
                    analysisMapper.insert(analysis);
                    //构建markdown对象
                    Markdown markdown=Markdown.builder()
                            .fileUrl(fileUrl)
                            .taskId(analysis.getId())
                            .fileName(fileNameWithoutExtension)
                            .markdown(markdownResult)
                            .build();
                    //对markdownMapper做插入操作
                    markdownMapper.insert(markdown);
                    //构建RecordVO对象
                    if (!recordResult.equals("{}")){
                        //调用著录数据处理方法
                        Record record = ApiUtil.recordDeal(recordResult);
                        RecordVO recordVO=RecordVO.builder()
                                .taskId(analysis.getId())
                                .fileName(fileNameWithoutExtension)
                                .fileUrl(fileUrl)
                                .record(record)
                                .build();
                        recordMapper.insert(recordVO);
                    }else {
                        Record record=null;
                        RecordVO recordVO=RecordVO.builder()
                                .taskId(analysis.getId())
                                .fileName(fileNameWithoutExtension)
                                .fileUrl(fileUrl)
                                .build();
                        recordMapper.insertWithNoRecord(recordVO);
                    }

                    //处理 "图片"页面 相关数据
                    if (middleContent!=null){//如果middle_content里确实有数据
                        //首先获取到其中的pdf_info这一键值对的值(为JSON数组)
                        JSONArray pdfInfoArray = middleContent.optJSONArray("pdf_info");
                        if (pdfInfoArray!=null && pdfInfoArray.length()!=0){//如果对这个文档确实分析出了数据
                            List<Images> imagesList = ApiUtil.middle2images(analysis.getId(), pdfInfoArray);
                            if (imagesList!=null && imagesList.size()!=0){
                                imagesMapper.insert(imagesList);
                            }
                        }
                    }
                    //处理"表格页面"中最上面的图片数据和最下面的表格数据
                    if (middleContent!=null){
                        JSONArray pdfInfoArray = middleContent.optJSONArray("pdf_info");
                        //pdf_info里面确实有东西
                        if (pdfInfoArray!=null && pdfInfoArray.length()!=0){
                            List<FormImg> formImgList=ApiUtil.middle2Imgs(analysis.getId(), pdfInfoArray);
                            if (formImgList.size()!=0){
                                formImgMapper.insert(formImgList);
                            }
                            List<FormTable> formTableList=ApiUtil.middle2Table(analysis.getId(), pdfInfoArray);
                            if (formTableList!=null && formTableList.size()!=0){
                                formTableMapper.insert(formTableList);
                            }
                        }
                    }
                    //处理content_list中markush和实例分子的对应关系
                    if (contentList!=null && contentList.length()!=0){//如果content_list里面确实有东西
                        ApiUtil.dealMarAndNum(contentList,analysis.getId());
                    }



                    // TODO 暂时去掉(避免多余的时间等待)
                    //处理example数据
//                    if (exampleResult.length()!=0){//如果第一个api产生的examples.json里面确实有东西 那么就继续解析
//                        String exampleString = ApiUtil.exampleDeal1(exampleResult.toString(), fileNameWithoutExtension);
//                        //将example的api的返回结果转为json对象
//                        JSONObject exampleJsonResponse = new JSONObject(exampleString);
//                        String message = exampleJsonResponse.optString("message", "");
//                        if (message.equals("Processing completed.")){//如果example的api解析成功
//                            //将返回结果中的structured_example_output信息进行处理
//                            JSONArray jsonArray = exampleJsonResponse.optJSONArray("structured_example_output");
//                            if (jsonArray.length()!=0){//如果确实有数据 那么再继续
//                                List<Synthesis> synthesisList = ApiUtil.exampleDeal2(jsonArray);
//                                //后续要下载的数据
//                                String examplesResult = jsonArray.toString();
//
//                                Examples examples=Examples.builder()
//                                        .taskId(analysis.getId())
//                                        .fileName(fileNameWithoutExtension)
//                                        .fileUrl(fileUrl)
//                                        .synthesisList(synthesisList)
//                                        .build();
//
//                                //更新analysis的结束时间和其他的api的返回结果数据
//                                Analysis temAnalysis=Analysis.builder()
//                                        .id(analysis.getId())
//                                        .finishTime(LocalDateTime.now())
//                                        .examplesResult(examplesResult)
//                                        .build();
//                                analysisMapper.updateFinishTimeAndResults(temAnalysis);
//
//                                //操作成功 插入数据
//                                examplesService.insert(examples);
//                            }
//                        }
//                    }


                    //返回markdownVO对象
                    return MarkdownVO.builder()
                            .fileUrl(fileUrl)
                            .taskId(analysis.getId())
                            .markdownResult(markdownResult)
                            .build();
                }else {//如果请求响应的状态码不是200 则说明请求失败
                    String fileUrl=fileName;
                    //准备analysisMapper中的数据
                    Analysis analysis=Analysis.builder()
                            .userId(userId)
                            .fileName(file.getOriginalFilename())
                            .status("分析失败")
                            .fileUrl(fileUrl)
                            .createTime(createTime)
                            .build();
                    //对analysisMapper做插入操作
                    analysisMapper.insert(analysis);
                    throw new ServiceException(Constants.API_ERROR,Constants.API_ERROR_MESSAGE);
                }
            } catch (IOException e) {
                e.printStackTrace();
                throw new ServiceException(Constants.FILE_ERROR,"文件分析有误");
            }
        }, EXECUTOR);
    }

    // 创建一个不验证SSL证书的HttpClient
    private static CloseableHttpClient createHttpClient() throws IOException {
        try {
            // 创建一个不验证SSL证书的SSLContext
            SSLContext sslContext = SSLContextBuilder.create()
                    .loadTrustMaterial((chain, authType) -> true) // 允许所有证书
                    .build();

            return HttpClients.custom()
                    .setSSLContext(sslContext)
                    .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE) // 不验证主机名
                    .build();
        } catch (Exception e) {
            throw new IOException("Failed to create HttpClient with SSL context", e);
        }
    }

}
